/*
https://wivl.github.io/blog/posts/cpp17-multi-thread-zero-to-threadpool/
参考文档：
https://www.cnblogs.com/xiaokang-coding/p/18889729
https://zhuanlan.zhihu.com/p/650522122

C++ 多线程
头文件thread

线程创建
  std::thread 线程名(函数名， 参数1，参数2，... );
  std::thread 线程名([](){
    语句;
  });  // 用lambda表达式创建  ()可以省略
  线程创建了就会自动执行
  线程会在函数运行完毕后自动释放，不推荐利用其他方法强制结束线程，可能会因资源未释放而导致内存泄漏
  其他函数
  std::this_thread::get_id()  // 获取线程id
  std::this_thread::yield()  // 放弃线程执行 回到就绪状态
  std::this_thread::sleep_for(std::chrono:seconds(1))  // 暂停1s


线程结束方式
  启动了线程，你需要明确是要等待线程结束(加入式-join)，还是让其自主运行(分离式-detach)。

  detach：启动的线程自主在后台运行，当前的代码继续往下执行，不等待新线程结束。主线程不会等待子线程结束。如果主线程运行结束，程序则结束。
  join：等待启动的线程完成，才会继续往下执行。join后面的代码不会被执行，除非子线程结束。
  joinable: 检查线程是否可等待。在join之前最好检查一下线程是否可等待，避免了对已经 join 或 detach 过的线程再次操作，否则会崩溃。

  防止忘记join，用RAII风格的线程包装器
  注意
  1，线程是在thread对象被定义的时候开始执行的，而不是在调用join函数时才执行的，调用join函数只是阻塞等待线程结束并回收资源。
  2，分离的线程（执行过detach的线程）会在调用它的线程结束或自己结束时释放资源。
  3，没有执行join或detach的线程在程序结束时会引发异常
*/

#include <iostream>
#include <thread>

void do_some_work(int n1, int n2)
{
    std::cout << "thread id: " << std::this_thread::get_id() << std::endl;
    std::cout << "thread running..." << n1 << ", " << n2 << std::endl;
}

// 线程创建
void create_thread()
{
    std::cout << "---- create thread ----" << std::endl;
    // 创建方式1
    std::thread work1(do_some_work, 1, 2);

    // 创建方式2 lambda 表达式
    std::thread work2([]()
                      { std::cout << "this is lambda expression thread..." << std::endl; });

    work1.join();
    work2.join();
}

// 结束线程
void stop_thead()
{
    std::cout << "---- stop thread ----" << std::endl;
    std::thread work1(do_some_work, 3, 4);
    std::thread work2(do_some_work, 9, 8);
    work1.detach();
    std::cout << "aaa" << std::endl;

    if (work2.joinable())
        work2.join();
    std::cout << "bbb" << std::endl;
}

// 线程包装器 析构的时候自动join
class thread_guard
{
private:
    std::thread &t;

public:
    // 构造函数 接收线程引用
    explicit thread_guard(std::thread &t_) : t(t_) {}

    // 析构函数 自动join
    ~thread_guard()
    {
        if (t.joinable())
            t.join();
    }

    // 禁止复制
    thread_guard(const thread_guard &) = delete;
    thread_guard &operator=(const thread_guard &) = delete;
};

void test_raii()
{
    std::cout << "---- thread raii ----" << std::endl;
    std::thread t(do_some_work, 666, 999);
    thread_guard g(t);  // 创建守卫对象

    // 即使这里抛出异常，thread_guard的析构函数也会被调用，确保t被join
    std::cout << "主线程继续工作..." << std::endl;

    // 函数结束，g被销毁，自动调用t.join()
}

int main()
{
    create_thread();
    stop_thead();
    test_raii();
    return 0;
}